package com.dongbao.core.base;

import com.dongbao.common.AwardedInfoConstant;
import com.dongbao.data.Datacenter;
import com.dongbao.dialog.DHGToolWindow;
import com.dongbao.entity.AwardedInfo;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.impl.source.PsiImportListImpl;
import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl;
import com.intellij.psi.impl.source.tree.java.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CodeRulesCommonBase {

    private static final Logger LOGGER = Logger.getInstance(CodeRulesCommonBase.class);

    public List<PsiPackageStatementImpl> psiPackageStatements;

    public List<PsiWhiteSpaceImpl> psiWhiteSpaces;

    public List<PsiImportListImpl> psiImportListImpls;

    public List<PsiClassImpl> psiClassImpls;

    public VirtualFile afterFile;

    public XmlFileType xmlFile;

    public Project project;

    public PsiFile psiFile;

    public String level;

    public String code;

    public CodeRulesCommonBase(VirtualFile javaAfterFile,PsiFile psiFile,Project project){
        this.afterFile = javaAfterFile;
        this.project = project;
        this.psiFile = psiFile;
        initPsi();
    }

    public void initPsi(){
        /* 将文件路径转换为Psi抽象语法树 */
        if(this.psiFile == null){
            this.psiFile = PsiManager.getInstance(this.project).findFile(afterFile);
        }
        if((afterFile.getFileType() instanceof JavaFileType)){
            PsiElement[] childrens = this.psiFile.getChildren();
            /* 文件分析成PSI */
            psiPackageStatements = new ArrayList<PsiPackageStatementImpl>();
            psiWhiteSpaces = new ArrayList<PsiWhiteSpaceImpl>();
            psiImportListImpls = new ArrayList<PsiImportListImpl>();
            psiClassImpls = new ArrayList<PsiClassImpl>();
            for(PsiElement children:childrens){
                if(children instanceof PsiPackageStatementImpl){
                    psiPackageStatements.add((PsiPackageStatementImpl)children);
                }
                if(children instanceof PsiWhiteSpaceImpl){
                    psiWhiteSpaces.add((PsiWhiteSpaceImpl)children);
                }
                if(children instanceof PsiImportListImpl){
                    psiImportListImpls.add((PsiImportListImpl)children);
                }
                if(children instanceof PsiClassImpl){
                    psiClassImpls.add((PsiClassImpl)children);
                }
            }
        }else if((afterFile.getFileType() instanceof XmlFileType) && afterFile.getName().contains("Dao.xml")){
            this.xmlFile = (XmlFileType)afterFile.getFileType();
            LOGGER.info("666");
        }

    }



    /**
     * 封装file和错误信息
     * */
    public void packDeduction(List<AwardedInfo> deduction,VirtualFile curAfterFile,String className,String packgName,String mothodName,String describe,Integer beginline,Integer endline){
        AwardedInfo awardedInfo=new AwardedInfo();
        awardedInfo.setVirtualFile(curAfterFile);
        awardedInfo.setFileName(curAfterFile.getName());
        awardedInfo.setScore(2);
        awardedInfo.setBeginline(beginline);
        awardedInfo.setEndline(endline);
        awardedInfo.setBegincolumn(0);
        awardedInfo.setEndcolumn(0);
        awardedInfo.setRule(describe());
        awardedInfo.setRuleset(describe());
        awardedInfo.setDescribe(describe);
        awardedInfo.setJavaPackage(packgName);
        awardedInfo.setJavaClass(className);
        awardedInfo.setJavaMethod(mothodName==null?"-":mothodName);
        awardedInfo.setType(AwardedInfoConstant.IDEA_CODE_ANALYSIS);
        awardedInfo.setLevel(this.level);
        awardedInfo.setCode(this.code);
        deduction.add(awardedInfo);
    }

    /**
     * 封装file和错误信息
     * */
    public void packDeduction(List<AwardedInfo> deduction,String className,String packgName,String mothodName,String describe,Integer beginline,Integer endline){
        AwardedInfo awardedInfo=new AwardedInfo();
        awardedInfo.setVirtualFile(afterFile);
        awardedInfo.setFileName(afterFile.getName());
        awardedInfo.setScore(2);
        awardedInfo.setBeginline(beginline);
        awardedInfo.setEndline(endline);
        awardedInfo.setBegincolumn(0);
        awardedInfo.setEndcolumn(0);
        awardedInfo.setRule(describe());
        awardedInfo.setRuleset(describe());
        awardedInfo.setDescribe(describe);
        awardedInfo.setJavaPackage(packgName);
        awardedInfo.setJavaClass(className);
        awardedInfo.setJavaMethod(mothodName==null?"-":mothodName);
        awardedInfo.setType(AwardedInfoConstant.IDEA_CODE_ANALYSIS);
        awardedInfo.setLevel(this.level);
        awardedInfo.setCode(this.code);
        deduction.add(awardedInfo);
    }

    /**
     * 封装file和错误信息
     * */
    public void packDeduction(List<AwardedInfo> deduction,String className,String packgName,String mothodName,String describe){
        packDeduction(deduction,className,packgName,mothodName,describe,null,null);
    }

    /**
     * 验证内容表述
     * */
    public String describe(){
        return null;
    };



    /**
     * 类、方法中的每一行代码
     * */
    public void runAllExpressionRow(List<AwardedInfo> deduction){
        /* 执行分析当前class是否负责当前规则 */
        PsiAnnotation[] annotations = psiClassImpls.get(0).getModifierList().getAnnotations();
        for(PsiClassImpl psiClass:psiClassImpls){
            /* 获取所有方法 */
            PsiMethod[] allMethods = psiClass.getMethods();
            for(PsiMethod method:allMethods){
                /* 从方法中查到看是否存在for循环 */
                PsiElement[] children = method.getBody().getChildren();
                for(PsiElement childrenItem:children){
                    this.validExp(childrenItem,deduction,psiClass,method);
                }
            }
        }
    }


    /**
     * 处理IF内逻辑代码 判断是否存在for
     * */
    public void ifCode(PsiElement element,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){
        /* 从IF中取出代码块 */
        PsiElement psiElement = Arrays.stream(element.getChildren()).filter(item -> item instanceof PsiBlockStatementImpl).findAny().orElse(null);
        if(psiElement==null){
            return ;
        }
        PsiElement ifBody = psiElement.getLastChild();
        PsiElement[] children = ifBody.getChildren();
        /* 使用循环过滤掉无限元素与if或者for循环 */
        for (PsiElement child : children) {
            this.validExp(child,deduction,psiClass,method);
        }
    }

    /**
     * 处理for循环节点中的代码,判断是否存在数据库操作
     * */
    public void forBody(PsiElement childrenItem,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){
        /* 获取for循环中的所有子节点 */
        if(childrenItem.getChildren().length==0){
            return ;
        }
        PsiElement psiElement = Arrays.stream(childrenItem.getChildren()).filter(item -> item instanceof PsiBlockStatementImpl).findAny().orElse(null);
        if(psiElement==null){
            return ;
        }
        PsiElement ifBody = psiElement.getLastChild();
        PsiElement[] forChildreElements = ifBody.getChildren();
        /* 去掉所有子节点中的注释 */
        List<PsiElement> filterChildreElements = Arrays.stream(forChildreElements).filter(item -> {
            return !(item instanceof PsiComment);
        }).collect(Collectors.toList());
        /* 遍历所有节点 判断是否存在if for 或者当前方法是操作数据库的语句 */
        for(PsiElement elementRow:filterChildreElements){
            this.validExp(elementRow,deduction,psiClass,method);
        }
    }

    /**
     * 判断表达式是否存在操作数据库的关键字
     * */
    public void validExp(PsiElement elementRow,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){
        /* 判断当前节点是否是for循环节点 */
        if(elementRow instanceof PsiForStatementImpl){
            forBody(elementRow,deduction,psiClass,method);
        }
        /* 判断是否是if,如果是if标签则再进到if里面去处理内部代码判断 */
        if(elementRow instanceof PsiIfStatementImpl){
            ifCode(elementRow,deduction,psiClass,method);
        }
        /* 判断是否是表达式 */
        if(elementRow instanceof PsiExpressionStatement){
            this.validExpUse(elementRow,deduction,psiClass,method);
        }
        /* 判断是否是声明变量的操作 */
        if(elementRow instanceof PsiDeclarationStatementImpl){
            this.validDeclarationUse(elementRow,deduction,psiClass,method);
        }
        this.validAll(elementRow,deduction,psiClass,method);
    }

    /**
     * 方法所有调用的解析事件
     * */
    public void validAll(PsiElement elementRow,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){

    }

    /**
     * 方法调用表达式解析事件
     * */
    public void validExpUse(PsiElement elementRow,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){

    }

    /**
     * 声明变量表达式解析事件
     * */
    public void validDeclarationUse(PsiElement elementRow,List<AwardedInfo> deduction,PsiClassImpl psiClass,PsiMethod method){

    }

}
